import axios from 'axios'
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse, Canceler } from 'axios'
import { message } from 'antd'
import type { BaseResponse } from './types'

// 创建实例
const http: AxiosInstance = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL,
  timeout: 10_000,
})

// 防抖重复请求：url + method 做 key
const pendingMap = new Map<string, Canceler>()
const generateKey = (config: AxiosRequestConfig) =>
  `${config.url}_${config.method}`

http.interceptors.request.use(
  (config) => {
    // 防抖
    const key = generateKey(config)
    pendingMap.get(key)?.() // 取消旧的
    config.cancelToken = new axios.CancelToken((c) => pendingMap.set(key, c))

    // Token
    const token = localStorage.getItem('token')
    if (token) {
      config.headers!.Authorization = `Bearer ${token}`
    }
    return config
  },
  (error) => Promise.reject(error)
)

http.interceptors.response.use(
  (response: AxiosResponse<BaseResponse>) => {
    pendingMap.delete(generateKey(response.config))

    const { code, message: msg, data } = response.data
    if (code === 0) return data // 约定 code=0 为成功

    // 业务错误统一提示
    message.error(msg || '系统繁忙')
    return Promise.reject(new Error(msg))
  },
  (error) => {
    if (axios.isCancel(error)) return Promise.reject(error)

    const msg = error.response?.data?.message || error.message || '网络异常'
    message.error(msg)
    return Promise.reject(error)
  }
)

// 泛型工具函数
export async function GET<T = unknown>(
  url: string,
  params?: object,
  config?: AxiosRequestConfig
) {
  const { data } = await http.get<BaseResponse<T>>(url, { params, ...config })
  return data
}

export async function POST<T = unknown>(
  url: string,
  data?: object,
  config?: AxiosRequestConfig
) {
  const res = await http.post<BaseResponse<T>>(url, data, config)
  return res.data
}

export async function PUT<T = unknown>(
  url: string,
  data?: object,
  config?: AxiosRequestConfig
) {
  const res = await http.put<BaseResponse<T>>(url, data, config)
  return res.data
}

export async function DELETE<T = unknown>(
  url: string,
  params?: object,
  config?: AxiosRequestConfig
) {
  const res = await http.delete<BaseResponse<T>>(url, { params, ...config })
  return res.data
}

// 上传 / 下载进度
export const upload = (url: string, formData: FormData, onProgress?: (p: number) => void) =>
  http.post(url, formData, {
    headers: { 'Content-Type': 'multipart/form-data' },
    onUploadProgress: (e) => onProgress?.(Math.round((e.loaded * 100) / (e.total || 1))),
  })

export const download = (url: string, params?: object, filename?: string) =>
  http
    .get(url, { params, responseType: 'blob' })
    .then((res) => {
      const blob = new Blob([res.data])
      const link = document.createElement('a')
      link.href = URL.createObjectURL(blob)
      link.download = filename || 'download'
      link.click()
      URL.revokeObjectURL(link.href)
    })